package com.y.fund.utils;


import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Set;

public class ReflectUtil {

    public static final Set<Class> BasicDataTypes = new HashSet<Class>();

    static {
        BasicDataTypes.add(Integer.class);
        BasicDataTypes.add(Long.class);
        BasicDataTypes.add(Short.class);
        BasicDataTypes.add(Float.class);
        BasicDataTypes.add(Double.class);
        BasicDataTypes.add(Boolean.class);
        BasicDataTypes.add(Byte.class);
        BasicDataTypes.add(Character.class);
        BasicDataTypes.add(String.class);
    }
    
	/**
	 * 将父类的属性值设置给子类
	 * @param father
	 * @param child
	 * @throws Exception
	 * 
	 * 子类的属性给父类可以直接通过强制转化即可
	 * BusiInfoIn busiInfo =new BusiInfoIn();  
		busiInfo=(BusiInfoIn)busiInfoIn_his; 
	 */
	public static void fatherToChild(Object father, Object child)throws Exception{
		 if(!(child.getClass().getSuperclass()==father.getClass())){
			 throw new Exception("child不是father的子类");
		 }
		 Class fatherClass= father.getClass();
		 Field[] ff = fatherClass.getDeclaredFields();
		 for(int i=0;i<ff.length;i++){
			 Field f=ff[i];//取出每一个属性，如deleteDate
//			 Class type=f.getType();
			 Method m=fatherClass.getMethod("get"+ UpperHeadChar(f.getName()));//方法getDeleteDate
			 Object obj=m.invoke(father);//取出属性值			 
			 f.set(child,obj);
			
			 /*
			  * 高手，有个疑问，对于BusiInfoIn父类的属性修饰符为private,这会报错，如何解决？
			  * 高手已经给提示了“Class type=f.getType();  ”
				 部分代码稍微改动下，如下：
				 Method m2 = childClass.getMethod("set" + upperHeadChar(f.getName()),type);
				 m2.invoke(child, new Object[]{obj}) ;//设置子类值
			  */
			 
			 
		 }
	 }

	/** 利用getter和setter方法将对象的值复制
	 * @param sourceObj
	 * @param targetObj
	 * @param ignoreId 是否忽略copy id值，如果值为true，则忽略JPAObj的ID和version属性；
	 * @throws Exception
	 */
	public static <T> T copyIgnoreId(Object sourceObj, T targetObj, boolean ignoreId)throws Exception{
		if(null==sourceObj || null==targetObj) {
			throw new Exception("源对像或目标对象为空");
		}

		Set<Method> setms = getSetterMethods(targetObj.getClass(), true);
		if(null==setms || setms.size()<1) {
			return targetObj;
		}
		Class srcClazz = sourceObj.getClass();
		for(Method sm : setms) {
			if(ignoreId &&
					("setId".equalsIgnoreCase(sm.getName()) || "setVersion".equalsIgnoreCase(sm.getName()))){
				/*忽略ID值的copy */
				continue;
			}
			String getMethodName = "get" + sm.getName().substring(3);
			/**获取源对象的getter方法 */
			Method gm = null;
			try{
				gm = srcClazz.getMethod(getMethodName);
			}catch(Exception ee) {
				/**没有对应的getter方法就会报错，忽略不做处理； */
				ee = null;
			}
			if(null != gm) {
				/*取出源对象的属性值	*/
				Object obj= gm.invoke(sourceObj);
				sm.invoke(targetObj, obj);
			}
		}
		return targetObj;
	}

    /** 从对象实例中获取字段的值 */
    public static Object getFieldValue(Object instance, Field field){
    	try {
    		field.setAccessible(true);
    		if (instance instanceof Class) {
    			// 静态字段获取时对象为null
        		return field.get(null);
    		}
    		return field.get(instance);
    	}catch(Exception ex) {
    		ex.printStackTrace();
    	}
    	return null;
    }
    
	/**
     * 反射取得 类 中对应属性的名
     * @param clazz 要获取属性列表 的 类
     * @param includeSuper 是否需要获取父类的属性名
     * @return
     */
    public static Set<Field> getDeclaredFields(Class clazz, boolean includeSuper){
        Field[] fields = clazz.getDeclaredFields();
        Set<Field> fieldset = new HashSet<Field>();
        fieldset.addAll(Arrays.asList(fields));
        if(includeSuper && clazz.getSuperclass()!=null){
        	fieldset.addAll(getDeclaredFields(clazz.getSuperclass(), includeSuper));
        }
        return fieldset;
    }
     

    /**
     * 反射取得 类 中对应属性的名
     * @param clazz 要获取方法列表 的类
     * @param includeSuper 是否需要获取父类的属性名
     * @return
     */
    public static Set<Method> getDeclaredMethods(Class clazz, boolean includeSuper){
    	Method[] methods = clazz.getDeclaredMethods();
        Set<Method> methodset = new HashSet<Method>();
        methodset.addAll(Arrays.asList(methods));
        if(includeSuper && clazz.getGenericSuperclass()!=null){
        	Set<Method> superMethods = getDeclaredMethods(clazz.getSuperclass(), includeSuper);
        	if(null!=superMethods && superMethods.size()>0) {
        		boolean noExist = true;
        		for(Method sm : superMethods) {
        			noExist = true;
        			/** 遍历 原来子类是否已经存在此方法名，如果存在了，则说明已经重载了，抛弃超类的相同方法 */
        			for(Method cm : methodset) {
        				if(cm.getName().equals(sm.getName())) {
        					noExist = false;
        					break;
        				}
        			}
        			if(noExist) {
        				methodset.add(sm);
        			}
        		}
        	}
        }
        return methodset;
    }

    /** 
     * 	 反射取得 类 中的所有setter方法
     * @param clazz 要获取方法列表 的类
     * @param includeSuper 是否需要获取父类的属性名
     * @return
     */
    public static Set<Method> getSetterMethods(Class clazz, boolean includeSuper){
    	Method[] methods = clazz.getDeclaredMethods();
        Set<Method> methodset = new HashSet<Method>();
        if(null!=methods && methods.length>0) {
        	for(Method m : methods) {
        		if(m.getName().toLowerCase().startsWith("set") && m.getParameterCount() > 0) {
        			/*以set开头，并且存在参数 */
        	        methodset.add(m);
        		}
        	}
        }
        if(includeSuper && clazz.getGenericSuperclass()!=null){
        	Set<Method> superMethods = getSetterMethods(clazz.getSuperclass(), includeSuper);
        	if(null!=superMethods && superMethods.size()>0) {
        		boolean noExist = true;
        		for(Method sm : superMethods) {
        			noExist = true;
        			/** 遍历 原来子类是否已经存在此方法名，如果存在了，则说明已经重载了，抛弃超类的相同方法 */
        			for(Method cm : methodset) {
        				if(cm.getName().equals(sm.getName())) {
        					noExist = false;
        					break;
        				}
        			}
        			if(noExist) {
        				methodset.add(sm);
        			}
        		}
        	}
        }
        return methodset;
    }

    /** 
     * 	 反射取得 类【及父类】 中的所有公共访问【public修饰符修饰】的getter方法
     * @param clazz 要获取方法列表 的类
     * @return
     */
    public static Set<Method> getPubGetterMethods(Class clazz){
    	Method[] methods = clazz.getMethods();
        Set<Method> methodset = new HashSet<Method>();
        if(null!=methods && methods.length>0) {
        	for(Method m : methods) {
        		if("getClass".equals(m.getName())) {
        			/* 排除 Object的getClass()方法 */
        			continue;
        		}
        		if(m.getName().toLowerCase().startsWith("get") && m.getParameterCount() < 1) {
        			/*以get开头，并且无参数 */
        	        methodset.add(m);
        		}
        	}
        }
        return methodset;
    }
	
	/**
	 * 取Bean的属性和值对应关系的MAP
	 * @param bean
	 * @return Map
	 */
	public static Map<String, String> getFieldValueMap(Object bean) {
		Class<?> cls = bean.getClass();
		Map<String, String> valueMap = new HashMap<String, String>();
		Method[] methods = cls.getDeclaredMethods();
		Field[] fields = cls.getDeclaredFields();
		for (Field field : fields) {
			try {
				String fieldType = field.getType().getSimpleName();
				String fieldGetName = parseGetterName(field.getName());
				if (!existsMethod(methods, fieldGetName)) {
					continue;
				}
				Method fieldGetMet = cls.getMethod(fieldGetName);
				Object fieldVal = fieldGetMet.invoke(bean);
				String result = null;
				if ("Date".equals(fieldType)) {
					result = fmtDate((Date) fieldVal);
				} else {
					if (null != fieldVal) {
						result = String.valueOf(fieldVal);
					}
				}
				valueMap.put(field.getName(), result);
			} catch (Exception e) {
				continue;
			}
		}
		return valueMap;
	}

	/**
	 * set属性的值到Bean
	 * 
	 * @param bean
	 * @param valMap
	 */
	public static void setFieldValue(Object bean, Map<String, String> valMap) {
		Class<?> cls = bean.getClass();
		// 取出bean里的所有方法
		Method[] methods = cls.getDeclaredMethods();
		Field[] fields = cls.getDeclaredFields();

		for (Field field : fields) {
			try {
				String fieldSetName = parseSetterName(field.getName());
				if (!existsMethod(methods, fieldSetName)) {
					continue;
				}
				Method fieldSetMet = cls.getMethod(fieldSetName, field.getType());
				String  fieldKeyName = field.getName();
				String value = valMap.get(fieldKeyName);
				if (null != value && !"".equals(value)) {
					String fieldType = field.getType().getSimpleName();
					if ("String".equals(fieldType)) {
						fieldSetMet.invoke(bean, value);
					} else if ("Date".equals(fieldType)) {
						Date temp = parseDate(value);
						fieldSetMet.invoke(bean, temp);
					} else if ("Integer".equals(fieldType)
							|| "int".equals(fieldType)) {
						Integer intval = Integer.parseInt(value);
						fieldSetMet.invoke(bean, intval);
					} else if ("Long".equalsIgnoreCase(fieldType)) {
						Long temp = Long.parseLong(value);
						fieldSetMet.invoke(bean, temp);
					} else if ("Double".equalsIgnoreCase(fieldType)) {
						Double temp = Double.parseDouble(value);
						fieldSetMet.invoke(bean, temp);
					} else if ("Boolean".equalsIgnoreCase(fieldType)) {
						Boolean temp = Boolean.parseBoolean(value);
						fieldSetMet.invoke(bean, temp);
					} else {
						System.out.println("not supper type" + fieldType);
					}
				}
			} catch (Exception e) {
				continue;
			}
		}
	}

	/**
	 * 格式化string为Date
	 * 
	 * @param datestr
	 * @return date
	 */
	public static Date parseDate(String datestr) {
		if (null == datestr || "".equals(datestr)) {
			return null;
		}
		try {
			String fmtstr = null;
			if (datestr.indexOf(':') > 0) {
				fmtstr = "yyyy-MM-dd HH:mm:ss";
			} else {
				fmtstr = "yyyy-MM-dd";
			}
			SimpleDateFormat sdf = new SimpleDateFormat(fmtstr, Locale.UK);
			return sdf.parse(datestr);
		} catch (Exception e) {
			return null;
		}
	}

	/**
	 * 日期转化为String
	 * 
	 * @param date
	 * @return date string
	 */
	public static String fmtDate(Date date) {
		if (null == date) {
			return null;
		}
		try {
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss",
					Locale.US);
			return sdf.format(date);
		} catch (Exception e) {
			return null;
		}
	}


	/**
	 *   根据属性名称获取此属性的Getter方法
	 * @param methods Method[]
	 * @param fieldName
	 */
	public static Method getGetterByFieldName(Set<Method> methods, String fieldName) {
		return getMethodByName(methods, parseGetterName(fieldName));
	}
	
	/**
	 * 拼接在某属性的 set方法
	 * @param fieldName
	 * @return String
	 */
	public static String parseSetterName(String fieldName) {
		if(StrUtil.isBlank(fieldName)) {
			return null;
		}
		int startIndex = 0;
		if (fieldName.charAt(0) == '_') {
			startIndex = 1;
		}
		return "set"
				+ fieldName.substring(startIndex, startIndex + 1).toUpperCase()
				+ fieldName.substring(startIndex + 1);
	}

	/**
	 * 拼接某属性的 get方法
	 * @param fieldName
	 * @return String
	 */
	public static String parseGetterName(String fieldName) {
		if(StrUtil.isBlank(fieldName)) {
			return null;
		}
		int startIndex = 0;
		if (fieldName.charAt(0) == '_') {
			startIndex = 1;
		}
		return "get"
				+ fieldName.substring(startIndex, startIndex + 1).toUpperCase()
				+ fieldName.substring(startIndex + 1);
	}

	/** 根据某属性的 get方法名称获取实际方法
	 * @param methods Method[]
	 * @param fieldMethodName
	 */
	public static Method getMethodByName(Method[] methods, String fieldMethodName) {
		if(null==methods || StrUtil.isBlank(fieldMethodName)) {
			return null;
		}
		for (Method met : methods) {
			if (fieldMethodName.equals(met.getName())) {
				return met;
			}
		}
		return null;
	}

	/**
	 * 判断是否存在某属性的 get方法
	 * @param methods Method[]
	 * @param fieldMethodName
	 */
	public static boolean existsMethod(Method[] methods, String fieldMethodName) {
		return (null != getMethodByName(methods, fieldMethodName));
	}
	
	/**
	 * 判断是否存在某属性的 get方法
	 * @param methods Set<Method>
	 * @param fieldMethodName
	 */
	public static boolean existsMethod(Set<Method> methods, String fieldMethodName) {
		return (null != getMethodByName(methods, fieldMethodName));
	}

	/** 根据某属性的 getter方法名称获取实际方法
	 * @param methods Set<Method>
	 * @param fieldMethodName
	 */
	public static Method getMethodByName(Set<Method> methods, String fieldMethodName) {
		if(null==methods || StrUtil.isBlank(fieldMethodName)) {
			return null;
		}
		for (Method met : methods) {
			if (fieldMethodName.equals(met.getName())) {
				return met;
			}
		}
		return null;
	}

    /** 遍历获取对象及对象父类的属性及属性值 */
  public static LinkedHashMap<String, Object> getField$Vals(Object o, Class cls, LinkedHashMap<String, Object> fkv) throws IllegalArgumentException, IllegalAccessException{
  	LinkedHashMap<String, Object> tfkv = new LinkedHashMap<String, Object>();
  	tfkv.putAll(fkv);
  	if(cls == null){
  		return tfkv;
  	}
      Field[] fields = cls.getDeclaredFields();
      for(int i=0; i<fields.length; i++){
          Field f = fields[i];
          f.setAccessible(true);
          if(!tfkv.containsKey(f.getName())){//如果已经存在则不取值了，以免父类的属性覆盖子类属性
          	tfkv.put(f.getName(), ""+f.get(o));/*注意，也不能用(String)强制转换，否则当属性为Integer等类型时会报类型错误*/
          }
       } 
      return getField$Vals(o, cls.getSuperclass(), tfkv);
   }
  
  /** 数据对象的每个属性及属性值的拼接成的字符串 */
  public static String toString(Object e) throws Exception{
  	if(null == e){
  		return "{}";
  	}
      Class cls = e.getClass();
      LinkedHashMap<String, Object> fkv = new LinkedHashMap<String, Object>();
      fkv = getField$Vals(e, cls, fkv);
      StringBuffer sb = new StringBuffer("{");
      for(String fn : fkv.keySet()){
          /*fkv.put(f.getName(), (String) f.get(e));
          System.out.println("属性名:" + f.getName() + " 属性值:" + f.get(e));*/
          sb.append("\"").append(fn).append("\":").append("\"").append(fkv.get(fn)).append("\"");
      }
      sb.append("}");
      return sb.toString();
  }

	 /**
	  * 将属性的首字母大写，以便与get|set组成getter|setter方法
	  * 首字母大写，in:deleteDate，out:DeleteDate
	  */
	 public static String UpperHeadChar(String in){
		 if(null==in) {
			 return null;
		 }
		 String head=in.substring(0,1);
		 return (head.toUpperCase()+in.substring(1));
	 }

}
